//------------------------------------------------------------------------------
//	file patch.cpp
//	brief
//		Single Patch file for Shruthi.
//
//	$Id: $
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//	Copyright and Disclaimer Notice
//
//	Copyright (c) 2013-2014 A.C. Verbeck
//
//	This file is part of Shruthi Patch Reader (SPR)
//
//	Shruthi Patch Reader (SPR) is free software: you can redistribute it and/or modify
//	it under the terms of the GNU General Public License as published by
//	the Free Software Foundation, either version 3 of the License, or
//	(at your option) any later version.
//
//	Shruthi Patch Reader (SPR) is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//	GNU General Public License for more details.
//
//	You should have received a copy of the GNU General Public License
//	along with Shruthi Patch Reader (SPR).
//	If not, see <http://www.gnu.org/licenses/>.
//
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//	Original Header
//------------------------------------------------------------------------------
// Copyright 2009 Olivier Gillet.
//
// Original Author: Olivier Gillet (ol.gillet@gmail.com)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// -----------------------------------------------------------------------------
//
// Patch definition. The order of the fields must match the numbering of the
// parameters defined later. Contains methods for packing/unpacking to a
// buffer of bytes (the compression is not optimal, but a more optimal
// compression that would use, for example, the MSB of all parameters in the
// 0-127 range, would result in a high code size).
// Also includes code for checking whether a buffer looks like a reasonable
// patch.
// -----------------------------------------------------------------------------

//------------------------------------------------------------------------------
//	Environment
//------------------------------------------------------------------------------
#include <stdio.h>
#include <stdint.h>																//	Standard int types

#include "patch.h"

static const char* mod_src_str[] = {
	"LFO 1",		"LFO 2",	"SEQ",		"SEQ 1",							//	0x00 .. 0x03
	"SEQ 2",		"STEP",		"WHEEL",	"AFTERTOUCH",						//	0x04 .. 0x07
	"PITCH_BEND",	"OFFSET",	"CV 1",		"CV 2",								//	0x08 .. 0x0b
	"CV 3",			"CV 4",		"CC A",		"CC B",								//	0x0c .. 0x0f
	"CC C",			"CC D",		"NOISE",	"ENV 1",							//	0x10 .. 0x13
	"ENV 2",		"VELOCITY",	"RANDOM",	"NOTE",								//	0x14 .. 0x17
	"GATE",			"AUDIO",	"OP 1",		"OP 2",								//	0x18 .. 0x1b
	"TRIG 1",		"TRIG 2",	"VALUE 4",	"VALUE 8",							//	0x1c .. 0x1f
	"VALUE 16",		"VALUE 32"													//	0x20 .. 0x21
};

static const char* mod_dest_str[] = {
	"FILTER CUTOFF", "VCA",	"PWM 1", "PWM 2",
	"VCO 1", "VCO 2", "VCO 1/2 COARSE", "VCO 1/2 FINE",
	"MIX BALANCE", "MIX NOISE", "MIX SUB OSC", "FILTER RESONANCE",
	"CV 1", "CV 2", "ATTACK", "LFO 1", "LFO 2",
	"TRIGGER ENV 1", "TRIGGER ENV 2"
};

static const char* osc_str[] = {
	"NONE", "SAW", "SQUARE", "TRIANGLE",
	"CZ SAW", "CZ RESO", "CZ TRIANGLE", "CZ PULSE", "CZ SYNC",
	"QUAD SAW PAD", "FM",
	"WAVETABLE 1", "WAVETABLE 2", "WAVETABLE 3", "WAVETABLE 4",
	"WAVETABLE 5", "WAVETABLE 6", "WAVETABLE 7", "WAVETABLE 8",
	"WAVETABLE USER",
	"8BITLAND", "CRUSHED SINE", "DIRTY PWM", "FILTERED NOISE",
	"VOWEL", "WAVETABLE 9",
};

static const char* sub_osc_str[] = {
	"SQUARE 1", "TRIANGLE 1", "PULSE 1",
	"SQUARE 2", "TRIANGLE 2", "PULSE 2",
	"CLICK", "GLITCH", "BLOW", "METALLIC", "POP"
};

static const char* lfo_wf_str[] = {
	"TRIANGLE", "SQUARE", "SAMPLE HOLD", "RAMP", "STEP_SEQUENCER",
	"WAVE_1", "WAVE_2", "WAVE_3", "WAVE_4",
	"WAVE_5", "WAVE_6", "WAVE_7", "WAVE_8",
	"WAVE_9", "WAVE_10", "WAVE_11", "WAVE_12",
	"WAVE_13", "WAVE_14", "WAVE_15", "WAVE_16"
};

static const char* lfo_mode_str[] = {
	"FREE",	"SLAVE", "MASTER"
};

static const char* param_str[] = {
	"OSC 1 SHAPE",		"OSC 1 PARAMETER",	"OSC 1 TRANSPOSE",	"OSC MIX OPERATOR",
	"OSC 2 SHAPE",		"OSC 2 PARAMETER",	"OSC 2 TRANSPOSE",	"OSC 2 DETUNE",
	"MIX BALANCE",		"MIX SUB OSC",		"MIX NOISE",		"MIX SUB OSC SHAPE",
	"FILTER CUTOFF",	"FILTER RESONANCE",	"FILTER ENV",		"FILTER LFO",
	"ENV 1 ATTACK",		"ENV 1 DECAY",		"ENV 1 SUSTAIN",	"ENV 1 RELEASE",
	"ENV 2 ATTACK",		"ENV 2 DECAY",		"ENV 2 SUSTAIN",	"ENV 2 RELEASE",
	"LFO 1 WAVE",		"LFO 1 RATE",		"LFO 1 ATTACK",		"LFO 1 RETRIGGER",
	"LFO 2 WAVE",		"LFO 2 RATE",		"LFO 2 ATTACK",		"LFO 2 RETRIGGER",
	"MOD SOURCE",		"MOD DESTINATION",	"MOD AMOUNT",		"MOD ROW"
};

static const char* mix_op_str[] = {
	"SUM", "SYNC", "RING MOD", "XOR", "FUZZ",
	"CRUSH 4", "CRUSH 8",
	"FOLD", "BITS", "DUO",
	"PING PONG 2 step", "PING PONG 4 step", "PING PONG 8 step",
	"PING PONG SEQ mix",
};


static const char* cv_op_str[] = {
	"NONE", "SUM", "PRODUCT", "MAX", "MIN",
	"XOR", "GE", "LE", "QUANTIZE", "LAG PROCESSOR",
};

/*
static const char* fmode1_str[] = {
	"LP", "BP", "HP",
	"LP_COUPLED", "BP_COUPLED", "HP_COUPLED"
};

static const char* fmode2_str[] = {
	"PARALLEL_LP", "PARALLEL_BP", "PARALLEL_HP",
	"SERIAL_LP", "SERIAL_BP", "SERIAL_HP"
};
*/

void patch_dump(Patch* pp)
{
	printf("Oscillator 1 shape:%d (%s),", pp->osc[0].shape, osc_str[pp->osc[0].shape]);
	printf(" parameter:%d,", pp->osc[0].parameter);
	printf(" pitch transpose:%d,", pp->osc[0].range);

	uint8_t mix_op = pp->osc[0].option;
	printf(" mix operator:%d (%s)\n", mix_op, mix_op_str[mix_op]);

	printf("Oscillator 2 shape:%d (%s),", pp->osc[1].shape, osc_str[pp->osc[1].shape]);
	printf(" parameter:%d,", pp->osc[1].parameter);
	printf(" pitch transpose:%d,", pp->osc[1].range);
	printf(" detune:%d\n", pp->osc[1].option);

	printf("Oscillator sub shape:%d (%s)\n", pp->mix_sub_osc_shape, sub_osc_str[pp->mix_sub_osc_shape]);

	printf("Oscillator mix balance:%d,", pp->mix_balance);
	printf(" mix sub:%d,", pp->mix_sub_osc);
	printf(" mix noise:%d\n", pp->mix_noise);

	printf("\n");

	printf("Filter cutoff:%d,", pp->filter_cutoff);
	printf(" Resonance:%d,", pp->filter_resonance);

	printf(" Envelope:%d,", pp->filter_env);
	printf(" LFO:%d\n", pp->filter_lfo);

	printf("\n");

	printf("Envelope 1 attack:%d,", pp->env[0].attack);
	printf(" decay:%d,", pp->env[0].decay);
	printf(" sustain:%d,", pp->env[0].sustain);
	printf(" release:%d\n", pp->env[0].release);

	printf("Envelope 2 attack:%d,", pp->env[1].attack);
	printf(" decay:%d,", pp->env[1].decay);
	printf(" sustain:%d,", pp->env[1].sustain);
	printf(" release:%d\n", pp->env[1].release);

	printf("\n");

	printf("LFO 1 waveform:%d (%s),", pp->lfo[0].waveform, lfo_wf_str[pp->lfo[0].waveform]);
	printf(" rate:%d,", pp->lfo[0].rate);
	printf(" attack:%d,", pp->lfo[0].attack);
	printf(" retrigger mode:%d (%s)\n", pp->lfo[0].retrigger_mode, lfo_mode_str[pp->lfo[0].retrigger_mode]);

	printf("LFO 2 waveform:%d (%s),", pp->lfo[1].waveform, lfo_wf_str[pp->lfo[1].waveform]);
	printf(" rate:%d,", pp->lfo[1].rate);
	printf(" attack:%d,", pp->lfo[1].attack);
	printf(" retrigger mode:%d (%s)\n", pp->lfo[1].retrigger_mode, lfo_mode_str[pp->lfo[1].retrigger_mode]);

	printf("\n");

	for (uint32_t i=0; i<kModulationMatrixSize; i++) {
		uint8_t ms = pp->modulation_matrix.modulation[i].source;
		uint8_t md = pp->modulation_matrix.modulation[i].destination;
		uint8_t ma = pp->modulation_matrix.modulation[i].amount;

		printf("Modulation ID:%d:"	,i);
		printf(" src:%d (%s),",		ms, mod_src_str[ms]);
		printf(" dest:%d (%s),",	md, mod_dest_str[md]);
		printf(" amt:%d\n",			ma);
	}

	printf("\n");
	printf("Patch name: >");
	for (uint32_t i=0; i<kPatchNameSize; i++) {
		printf("%c"	,pp->name[i]);
	}
	printf("<\n");
	printf("\n");

#ifdef PORTAMENTO_SAVE_HACK
	printf("Portamento save:%d\n", pp->portamento_data);
#endif

	for (uint32_t i=0; i<4; i++) {
		uint8_t id = pp->assigned_parameters[i].id;
		uint8_t sp = pp->assigned_parameters[i].subpage;
		const char* id_str = param_str[pp->assigned_parameters[i].id];

		printf("Assignment ID:%d:"	,i);
		printf(" id:%d (%s),",id, id_str);
		printf(" subpage:%d\n",sp);
	}
	printf("\n");

	printf("Filter cutoff 2:%d,", pp->filter_cutoff_2);
	printf(" Resonance 2:%d\n", pp->filter_resonance_2);
	printf("Filter Topology:%d\n", pp->filter_topology_);

	printf("\n");
	printf("op data:");
	for (uint32_t i=0; i<4; i++) {
		printf(" %02x",pp->op_data_[i]);
	}
	printf("\n");
	uint8_t op_opr = (pp->op_data_[1] & 0x07) | ((pp->op_data_[0] & 0x80) ? 0x08 : 0x00);
	uint8_t op_in1 = pp->op_data_[0] & 0x3f;
	uint8_t op_in2 = ((pp->op_data_[1] & 0xf8) >> 3) | ((pp->op_data_[0] & 0x40) ? 0x20 : 0x00);
	printf("Operator 1: operator: %s input 1: %s input 2: %s\n",cv_op_str[op_opr], mod_src_str[op_in1], mod_src_str[op_in2]);

	op_opr = (pp->op_data_[3] & 0x07) | ((pp->op_data_[2] & 0x80) ? 0x08 : 0x00);
	op_in1 = pp->op_data_[2] & 0x3f;
	op_in2 = ((pp->op_data_[3] & 0xf8) >> 3) | ((pp->op_data_[2] & 0x40) ? 0x20 : 0x00);
	printf("Operator 2: operator: %s input 1: %s input 2: %s\n",cv_op_str[op_opr], mod_src_str[op_in1], mod_src_str[op_in2]);

	printf("\n\n");

	/*
		printf("Exclamation Mark:%02x\n", pp->exclamation_mark_);
		printf("Filter #1 Mode:%d (%s)\n", pp->filter_1_mode_, fmode1_str[pp->filter_1_mode_]);
		printf("Filter #2 Mode:%d (%s)\n", pp->filter_2_mode_, fmode2_str[pp->filter_2_mode_]);
		printf("\n");

		for (uint32_t i=0; i<2; i++) {
			uint8_t op_1 = pp->ops_[i].operands[0];
			uint8_t op_2 = pp->ops_[i].operands[1];
			uint8_t op   = pp->ops_[i].op;
			const char* ops  = op_str[pp->ops_[i].op];
			printf("operator %d: o1:%d, o2:%d, op:%d (%s)\n", i, op_1, op_2, op, ops);
		}
	*/
}

//
//	End: patch.cpp
//
